<template>
  <div 
    :class="[
      'bx-upload',
      'bx-glass',
      {
        'bx-upload--disabled': disabled,
        'bx-upload--drag': drag,
        'bx-upload--single': !multiple
      }
    ]"
    @click="handleClick"
    @dragover.prevent="handleDragOver"
    @dragleave.prevent="handleDragLeave"
    @drop.prevent="handleDrop"
  >
    <input
      ref="fileInput"
      type="file"
      :multiple="multiple"
      :accept="accept"
      :disabled="disabled"
      @change="handleFileChange"
      style="display: none;"
    />

    <div v-if="drag" class="bx-upload__drag-area">
      <BxIcon name="upload" class="bx-upload__drag-icon" />
      <p class="bx-upload__drag-text">将文件拖到此处，或 <em>点击上传</em></p>
    </div>

    <div v-else class="bx-upload__trigger">
      <BxButton :disabled="disabled">
        <BxIcon name="upload" /> 上传文件
      </BxButton>
    </div>

    <ul v-if="fileList.length > 0" class="bx-upload__file-list">
      <li 
        v-for="(file, index) in fileList"
        :key="file.name + index"
        class="bx-upload__file-item bx-glass"
      >
        <BxIcon name="file" class="bx-upload__file-icon" />
        <span class="bx-upload__file-name">{{ file.name }}</span>
        <span class="bx-upload__file-size">({{ formatFileSize(file.size) }})</span>
        <span :class="['bx-upload__file-status', `bx-upload__file-status--${file.status}`]">
          {{ file.status === 'success' ? '上传成功' : file.status === 'fail' ? '上传失败' : '上传中...' }}
        </span>
        <BxIcon 
          v-if="!disabled"
          name="x"
          class="bx-upload__file-delete"
          @click.stop="removeFile(index)"
        />
      </li>
    </ul>
  </div>
</template>

<script>
import { ref, watch } from 'vue'
import BxButton from '../basic/BxButton.vue'
import BxIcon from '../basic/BxIcon.vue'

export default {
  name: 'BxUpload',
  components: {
    BxButton,
    BxIcon
  },
  props: {
    modelValue: {
      type: Array,
      default: () => []
    },
    multiple: {
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    drag: {
      type: Boolean,
      default: false
    },
    accept: {
      type: String,
      default: ''
    },
    max: {
      type: Number,
      default: 0 // 0 means no limit
    },
    autoUpload: {
      type: Boolean,
      default: true
    },
    requestMethod: {
      type: Function,
      default: null
    }
  },
  emits: ['update:modelValue', 'change', 'success', 'fail', 'remove', 'progress'],
  setup(props, { emit }) {
    const fileInput = ref(null)
    const fileList = ref(props.modelValue.map(file => ({ ...file, status: 'success' })))

    watch(() => props.modelValue, (newVal) => {
      fileList.value = newVal.map(file => ({ ...file, status: 'success' }))
    }, { deep: true })

    const handleClick = () => {
      if (props.disabled) return
      fileInput.value.click()
    }

    const handleFileChange = (event) => {
      const files = Array.from(event.target.files)
      addFiles(files)
      fileInput.value.value = '' // Clear input to allow re-uploading same file
    }

    const handleDragOver = (event) => {
      if (props.disabled || !props.drag) return
      event.dataTransfer.dropEffect = 'copy'
    }

    const handleDragLeave = () => {
      // No specific action needed
    }

    const handleDrop = (event) => {
      if (props.disabled || !props.drag) return
      const files = Array.from(event.dataTransfer.files)
      addFiles(files)
    }

    const addFiles = (files) => {
      let newFiles = []
      for (const file of files) {
        if (props.max > 0 && fileList.value.length + newFiles.length >= props.max) {
          console.warn(`文件数量超出最大限制: ${props.max}`)
          break
        }
        newFiles.push({ raw: file, name: file.name, size: file.size, status: 'uploading' })
      }

      fileList.value = [...fileList.value, ...newFiles]
      emitChange()

      if (props.autoUpload) {
        newFiles.forEach(file => uploadFile(file))
      }
    }

    const uploadFile = async (file) => {
      if (!props.requestMethod) {
        console.warn('未提供 requestMethod，文件不会真正上传。')
        file.status = 'success'
        emitChange()
        emit('success', file)
        return
      }

      try {
        const response = await props.requestMethod(file.raw, (progressEvent) => {
          file.progress = Math.round((progressEvent.loaded * 100) / progressEvent.total)
          emit('progress', file, progressEvent)
        })
        file.status = 'success'
        file.response = response
        emit('success', file, response)
      } catch (error) {
        file.status = 'fail'
        file.error = error
        emit('fail', file, error)
      } finally {
        emitChange()
      }
    }

    const removeFile = (index) => {
      if (props.disabled) return
      const removed = fileList.value.splice(index, 1)[0]
      emitChange()
      emit('remove', removed)
    }

    const emitChange = () => {
      emit('update:modelValue', fileList.value)
      emit('change', fileList.value)
    }

    const formatFileSize = (bytes) => {
      if (bytes === 0) return '0 B'
      const k = 1024
      const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
      const i = Math.floor(Math.log(bytes) / Math.log(k))
      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
    }

    return {
      fileInput,
      fileList,
      handleClick,
      handleFileChange,
      handleDragOver,
      handleDragLeave,
      handleDrop,
      removeFile,
      formatFileSize
    }
  }
}
</script>

<style scoped>
.bx-upload {
  font-family: var(--bx-font-family);
  color: var(--bx-text-primary);
}

.bx-upload__drag-area {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 180px;
  border: 2px dashed var(--bx-glass-border);
  border-radius: var(--bx-radius-medium);
  background: var(--bx-glass-bg);
  backdrop-filter: var(--bx-glass-blur);
  cursor: pointer;
  transition: all var(--bx-transition-medium);
}

.bx-upload__drag-area:hover {
  border-color: rgba(0, 122, 255, 0.5);
  background: var(--bx-glass-bg-hover);
}

.bx-upload--disabled .bx-upload__drag-area {
  opacity: 0.6;
  cursor: not-allowed;
}

.bx-upload__drag-icon {
  font-size: 48px;
  color: var(--bx-text-tertiary);
  margin-bottom: 16px;
}

.bx-upload__drag-text {
  font-size: 16px;
  color: var(--bx-text-secondary);
}

.bx-upload__drag-text em {
  font-style: normal;
  color: rgba(0, 122, 255, 0.8);
}

.bx-upload__trigger {
  display: inline-block;
}

.bx-upload__file-list {
  list-style: none;
  padding: 0;
  margin-top: 16px;
}

.bx-upload__file-item {
  display: flex;
  align-items: center;
  padding: 8px 12px;
  margin-bottom: 8px;
  border: 1px solid var(--bx-glass-border);
  border-radius: var(--bx-radius-medium);
  background: var(--bx-glass-bg);
  backdrop-filter: var(--bx-glass-blur);
}

.bx-upload__file-icon {
  font-size: 18px;
  color: var(--bx-text-secondary);
  margin-right: 8px;
}

.bx-upload__file-name {
  flex: 1;
  font-size: 14px;
  color: var(--bx-text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.bx-upload__file-size {
  font-size: 12px;
  color: var(--bx-text-tertiary);
  margin-left: 8px;
}

.bx-upload__file-status {
  font-size: 12px;
  margin-left: 8px;
}

.bx-upload__file-status--uploading {
  color: orange;
}

.bx-upload__file-status--success {
  color: green;
}

.bx-upload__file-status--fail {
  color: red;
}

.bx-upload__file-delete {
  font-size: 14px;
  color: var(--bx-text-tertiary);
  cursor: pointer;
  margin-left: 8px;
}

.bx-upload__file-delete:hover {
  color: var(--bx-text-primary);
}

.bx-upload--single .bx-upload__file-list {
  max-width: 300px; /* Limit width for single file list */
}

/* Responsive */
@media (max-width: 768px) {
  .bx-upload__drag-area {
    min-height: 150px;
  }
  .bx-upload__drag-icon {
    font-size: 40px;
  }
  .bx-upload__drag-text {
    font-size: 14px;
  }
  .bx-upload__file-item {
    padding: 6px 10px;
  }
  .bx-upload__file-name {
    font-size: 13px;
  }
  .bx-upload__file-size,
  .bx-upload__file-status {
    font-size: 11px;
  }
}
</style>

